import opuslib
import pyaudio
import requests
import numpy as np

# 音频参数配置 (必须与编码端一致)
SAMPLE_RATE = 24000  # 采样率
CHANNELS = 1         # 声道数 (单声道)
FRAME_SIZE = 480  # 20ms @24kHz
BUFFER_SIZE = FRAME_SIZE * CHANNELS * 2  # 960字节

def create_opus_decoder():
    """创建 Opus 解码器"""
    return opuslib.Decoder(SAMPLE_RATE, CHANNELS)

def opus_to_float32(decoder, opus_data):
    """
    Opus -> float32 PCM 解码
    输出: numpy float32数组 [-1, 1]
    """
    # 解码为PCM字节数据 (int16格式)
    pcm_bytes = decoder.decode(opus_data, FRAME_SIZE)
    
    # 转换为numpy数组
    int16_array = np.frombuffer(pcm_bytes, dtype=np.int16)
    
    # 转换为float32 [-1, 1]
    return int16_array.astype(np.float32) / 32768.0

def play_opus_stream(url, text):
    # 创建Opus解码器
    decoder = create_opus_decoder()
    
    # 初始化音频播放
    p = pyaudio.PyAudio()
    stream = p.open(
        format=pyaudio.paInt16,
        channels=CHANNELS,
        rate=SAMPLE_RATE,
        output=True,
        frames_per_buffer=FRAME_SIZE
    )
    
    print("开始播放... (Ctrl+C 停止)")
    try:
        with requests.post(
                url,
                headers={"Content-Type": "text/plain"},
                data=text.encode('utf-8'),
                stream=True
            ) as r:
                r.raise_for_status()
                
                # 获取并播放音频数据
                for chunck in r.iter_content(chunk_size=None): # chunk_size=None表示按照服务端返回的块大小
                    if chunck:
                        # Opus解码
                        pcm_data = opus_to_float32(decoder, chunck)
                        
                        # 播放音频
                        stream.write(pcm_data.to_bytes())
            
    except KeyboardInterrupt:
        print("播放被用户中断")
    except Exception as e:
        print(f"播放过程中出现错误: {e}")
    finally:
        # 清理
        stream.stop_stream()
        stream.close()
        p.terminate()